package com.ruoyi.common.utils.file;

import com.ruoyi.common.config.MinIoProperties;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import javax.swing.tree.TreeNode;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.util.List;

/**
 * @Auther: lihongming
 * @Date: 2022-05-11 21:58
 * @Description: com.ruoyi.common.utils.file
 * @Version: 1.0
 */
@Slf4j
@Component
public class MinIoUtil {

    @Autowired
    MinIoProperties minIoProperties;

    private static MinioClient minioClient;

    /**
     * 初始化minio配置
     *
     * @param :
     * @return: void
     * @date : 2023/12/29
     */
    @PostConstruct
    public void init() {
        try {
            minioClient = MinioClient.builder()
                    // minio服务端地址URL
                    .endpoint(minIoProperties.getUrl())
                    // 用户名及密码（访问密钥/密钥）
                    .credentials(minIoProperties.getAccessKey(), minIoProperties.getSecretKey())
                    .build();

            createBucket(minIoProperties.getBucketName());
            createBucket(minIoProperties.getBucketOrgImg());
            createBucket(minIoProperties.getBucketSafeDoc());
            createBucket(minIoProperties.getBucketEdu());
        } catch (Exception e) {
            e.printStackTrace();
            log.error("初始化minio配置异常: 【{}】", e.fillInStackTrace());
        }
    }

    /**
     * 判断 bucket是否存在
     *
     * @param bucketName: 桶名
     * @return: boolean
     * @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static boolean bucketExists(String bucketName) {
        BucketExistsArgs build = BucketExistsArgs.builder().bucket(bucketName).build();
        return minioClient.bucketExists(build);
    }

    /**
     * 创建 bucket
     *
     * @param bucketName: 桶名
     * @return: void
     * @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static void createBucket(String bucketName) {
        BucketExistsArgs build = BucketExistsArgs.builder().bucket(bucketName).build();
        boolean isExist = minioClient.bucketExists(build);
        if (!isExist) {
            MakeBucketArgs bucket = MakeBucketArgs.builder().bucket(bucketName).build();
            minioClient.makeBucket(bucket);
        }
    }

    /**
     * 获取全部bucket
     *
     * @param :
     * @return: java.util.List<io.minio.messages.Bucket>
     * @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static List<Bucket> getAllBuckets() {
        return minioClient.listBuckets();
    }

    /**
     * 文件上传
     *
     * @param bucketName: 桶名
     * @param fileName:   文件名
     * @param filePath:   文件路径
     * @return: void
     * @date : @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static void upload(String bucketName, String fileName, String filePath) {
        UploadObjectArgs args = UploadObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .filename(filePath)
                .build();
        minioClient.uploadObject(args);
    }

    /**
     * 文件上传
     *
     * @param bucketName: 桶名
     * @param fileName:   文件名
     * @param stream:     文件流
     * @return: java.lang.String : 文件url地址
     * @date : 2023/12/29
     */
    public static String upload(String bucketName, String fileName, InputStream stream) {
        try {
            PutObjectArgs build = PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
                            stream, stream.available(), -1)
                    .build();
//        minioClient.putObject(bucketName, fileName, stream, new PutObjectOptions(stream.available(), -1));
            minioClient.putObject(build);
            return getFileUrl(bucketName, fileName);
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        } finally {
            try {
                stream.close();
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
        }
    }

    /**
     * 文件上传
     *
     * @param bucketName: 桶名
     * @param file:       文件
     * @return: java.lang.String : 文件url地址
     * @date : @date : 2023/12/29
     */
    public static String upload(String bucketName, MultipartFile file) {
        final InputStream is;
        try {
            is = file.getInputStream();
        } catch (IOException e) {
            throw new RuntimeException(e.getMessage());
        }
        final String fileName = file.getOriginalFilename();
        try {
            PutObjectArgs build = PutObjectArgs.builder().bucket(bucketName).object(fileName).stream(
                            is, is.available(), -1)
                    .build();
            minioClient.putObject(build);
            return getFileUrl(bucketName, fileName);
        } catch (Exception ex) {
            throw new RuntimeException(ex.getMessage());
        } finally {
            try {
                is.close();
            } catch (IOException e) {
                throw new RuntimeException(e.getMessage());
            }
        }

    }

    /**
     * 删除文件
     *
     * @param bucketName: 桶名
     * @param fileName:   文件名
     * @return: void
     * @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static void removeObject(String bucketName, String fileName) {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucketName)
                        .object(fileName)
                        .build());
    }

    /**
     * 删除指定版本号的对象
     *
     * @param bucket    桶名称
     * @param filename  文件名
     * @param versionId 版本号
     */
    @SneakyThrows(Exception.class)
    public static void removeObject(String bucket, String filename, String versionId) {
        minioClient.removeObject(
                RemoveObjectArgs.builder()
                        .bucket(bucket)
                        .object(filename)
                        .versionId(versionId)
                        .build());
    }

    /**
     * 下载文件
     *
     * @param bucketName: 桶名
     * @param fileName:   文件名
     * @param response:
     * @return: void
     * @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static void download(String bucketName, String fileName, HttpServletResponse response) {
        InputStream inputStream = minioClient.getObject(GetObjectArgs.builder()
                .bucket(bucketName)
                .object(fileName)
                .build());
        ComposeObjectArgs build = ComposeObjectArgs.builder().bucket(bucketName).object(fileName).build();
        // 获取对象的元数据
        StatObjectArgs argsStat = StatObjectArgs.builder().bucket(bucketName).object(fileName).build();
        final StatObjectResponse stat = minioClient.statObject(argsStat);
        response.setContentType(stat.contentType());
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
        IOUtils.copy(inputStream, response.getOutputStream());
        inputStream.close();
    }

    /**
     * 获取minio文件的下载地址
     *
     * @param bucketName: 桶名
     * @param fileName:   文件名
     * @return: java.lang.String
     * @date : 2023/12/29
     */
    @SneakyThrows(Exception.class)
    public static String getFileUrl(String bucketName, String fileName) {
        GetPresignedObjectUrlArgs args = GetPresignedObjectUrlArgs.builder().bucket(bucketName).object(fileName).method(Method.GET).build();
        return minioClient.getPresignedObjectUrl(args);
    }

}
